/**
 * Race.java
 *
 * Roslan's Remake of MOO in 3D using Ardor3D
 * (C) 2011 Roslan Amir. All rights reserved.
 */

package com.roslan.games.moo3d.data;

import com.ardor3d.math.MathUtils;
import com.roslan.games.moo3d.GameData;
import com.roslan.games.moo3d.data.Star.Environment;

/**
 * This class implements the race entity. It contains all the attributes for a race.
 * 
 * @author Roslan Amir
 * @version 1.0 - Jan 3, 2011
 */
public class Race {

	/**
	 * The list of player race names. {adjective, plural}
	 */
	private static final String[][] RACE_NAMES = {
		{"Human", "Humans"}, // 0
		{"Mrrshan", "Mrrshans"}, // 1
		{"Silicoid", "Silicoids"}, // 2
		{"Sakkra", "Sakkra"}, // 3
		{"Psilon", "Psilons"}, // 4
		{"Alkari", "Alkari"}, // 5
		{"Klackon", "Klackons"}, // 6
		{"Bulrathi", "Bulrathi"}, // 7
		{"Meklar", "Meklars"}, // 8
		{"Darlok", "Darloks"}}; // 9

	/**
	 * The list of description for the player races.
	 */
	private static final String[] RACE_DESCRIPTIONS = {
		"Expert traders and magnificient diplomats", // human
		"Superior gunners", // mrrshan
		"Immune to hostile planet environments", // silicoid
		"Increased population growth", // sakkra
		"Superior research techniques", // psilon
		"Superior pilots", // alkari
		"Increased worker production", // klackon
		"Terrific ground fighters", // bulrathi
		"Enhanced factory controls", // meklar
		"Supreme spies" }; // darlok

	/**
	 * The list of player race leader names.
	 */
	private static final String[][] LEADER_NAMES = {
		{ "Alexander", "Bladrov II", "Durash IV", "Johann III", "Lasitus", "Strader" },	// human
		{ "Mirana", "Jasana", "Miamar", "Prrsha", "Shandra", "Yalara" },				// mrrshan
		{ "Carnax", "Crystous", "Geode", "Granid", "Igneous", "Sedimin" },				// silicoid
		{ "Guanar", "Hissa", "Kryssta", "Saurak", "Sauron", "Tyranid" },				// sakkra
		{ "Dynalon", "Kelvan", "Meson", "Quark", "Tachaon", "Zygot" },					// psilon
		{ "Ariel", "Farseer", "Highsoar", "Redwing", "Sharpclaw", "Skylord" },			// alkari
		{ "Ixitixl", "Kaxal", "K'kalak", "Kikitik", "Klaquan", "Xantak" },				// klackon
		{ "Bullux", "Durpp", "Grunk", "Krungo", "Monch", "Smurch" },					// bulrath
		{ "CB-715", "INT-986", "M5-35", "QX-537", "TVC-15", "TX-1138" },				// meklar
		{ "Darquan", "Morfane", "Narzina", "Nazgur", "Shador", "Ssithra" } };			// darlok

	/**
	 * The total number of races that can be chosen.
	 */
	public static final int TOTAL_NO_OF_RACES = RACE_NAMES.length;

	/**
	 * How many BC to generate 1 unit of population. Initially 20BC, with Cloning 10BC, and with Adv Cloning 5BC.
	 */
	private static final int POPULATION_COST_INITIAL = 20;

//	private static final int POPULATION_COST_WITH_CLONING = 10;

//	private static final int POPULATION_COST_WITH_ADVANCED_CLONING = 5;

	/**
	 * How much production a unit of population produces. Initially, this is 0.5BC. At Planetology Level 25, this 1.0BC. At
	 * Planetology Level 40, this 1.5BC. At Planetology Level 50, this 2.0BC. Klackons starts out with 1.0BC.
	 */
	private static final double PRODUCTION_PER_POPULATION_INITIAL = 0.5f;

//	private static final double PRODUCTION_PER_POPULATION_LEVEL25 = 1.0f;

//	private static final double PRODUCTION_PER_POPULATION_LEVEL40 = 1.5f;

//	private static final double PRODUCTION_PER_POPULATION_LEVEL50 = 2.0f;

	private static final double KLACKON_PRODUCTION_PER_POPULATION_INITIAL = 1.0f;

//	private static final double KLACKON_PRODUCTION_PER_POPULATION_LEVEL25 = 1.5f;

//	private static final double KLACKON_PRODUCTION_PER_POPULATION_LEVEL40 = 2.0f;

//	private static final double KLACKON_PRODUCTION_PER_POPULATION_LEVEL50 = 2.5f;

	/**
	 * How many factories 1 unit of population can operate. Initially, this is 2.
	 */
	private static final int INITIAL_FACTORIES_PER_POPULATION = 2;

	/**
	 * How much a factory costs to construct. Initially, this is 10BC.
	 */
	private static final int FACTORY_COST_10 = 10;
//	private static final int FACTORY_COST_09 = 9;
//	private static final int FACTORY_COST_08 = 8;
//	private static final int FACTORY_COST_07 = 7;
//	private static final int FACTORY_COST_06 = 6;
//	private static final int FACTORY_COST_05 = 5;
//	private static final int FACTORY_COST_04 = 4;
//	private static final int FACTORY_COST_03 = 3;
//	private static final int FACTORY_COST_02 = 2;

	/**
	 * Rates of factory waste. Initially, this is 1BC per factory.
	 */
	private static final double WASTE_PER_FACTORY_100 = 1.0f;
//	private static final double WASTE_PER_FACTORY_080 = 0.8f;
//	private static final double WASTE_PER_FACTORY_060 = 0.6f;
//	private static final double WASTE_PER_FACTORY_040 = 0.4f;
//	private static final double WASTE_PER_FACTORY_020 = 0.2f;
//	private static final double WASTE_PER_FACTORY_000 = 0.0f;

	/**
	 * How much it costs to clean up a unit of waste. Initially, this is 0.5BC per unit of waste.
	 */
	private static final double CLEANUP_COST_PER_WASTE_INITIAL = 0.5f;
//	private static final double CLEANUP_COST_PER_WASTE_IMPROVED = 1.0f/3.0f;
//	private static final double CLEANUP_COST_PER_WASTE_ENHANCED = 0.2f;
//	private static final double CLEANUP_COST_PER_WASTE_ADVANCED = 0.1f;
//	private static final double CLEANUP_COST_PER_WASTE_COMPLETE = 0.05f;

	/**
	 * How much a missile base costs to construct. Initially, this is 245BC.
	 */
	private static final int INITIAL_MISSILE_BASE_COST = 245;

	/**
	 * The initial research ratios for each research area.
	 */
	private static final int INITIAL_WEAPONS_RP_RATIO = 16;
	private static final int INITIAL_PROPULSION_RP_RATIO = 18;
	private static final int INITIAL_PLANETOLOGY_RP_RATIO = 18;
	private static final int INITIAL_FORCEFIELD_RP_RATIO = 16;
	private static final int INITIAL_CONSTRUCTION_RP_RATIO = 16;
	private static final int INITIAL_COMPUTERS_RP_RATIO = 16;

	/**
	 * The starting scanner range for each player.
	 */
	private static final int INITIAL_SCANNER_RANGE = 3;

	/**
	 * Working variable.
	 */
	private static final boolean[] raceAssigned = new boolean[TOTAL_NO_OF_RACES];

	/**
	 * Working variable.
	 */
	private static final boolean[] bannerAssigned = new boolean[GameData.TOTAL_NO_OF_BANNERS];

	/**
	 * The index into the various arrays for this race.
	 */
	public final int raceIndex;

	/**
	 * The race name for this race.
	 */
//	public final String name;

	/**
	 * The index into the various banner color array.
	 */
	public final int bannerIndex;

	/**
	 * The leader name for this race. The reason it's String is because the player may enter any name he wishes.
	 */
	public final String leaderName;

	/**
	 * The maximum range the scanners can see for this race.
	 */
	public int scannerRange;

	/**
	 * The maximum range the ships can go for this race.
	 */
	public int shipRange;

	/**
	 * How many BC to generate 1 unit of population. Initially 20BC, with Cloning 10BC, and with Adv Cloning 5BC.
	 */
	public int populationCost;

	/**
	 * How much production a unit of population produces. Initially, this is 0.5BC. At Planetology Level 25, this 1.0BC. At
	 * Planetology Level 40, this 1.5BC. At Planetology Level 50, this 2.0BC. Klackons starts out with 1.0BC, then 1.5, then
	 * 2.0, then 2.5;
	 */
	public double productionPerPopulation;

	/**
	 * How many factories 1 unit of population can operate. Initially, this is 2.
	 */
	public int factoriesPerPopulation;

	/**
	 * How much a factory costs to construct. Initially, this is 10BC.
	 */
	public int factoryCost;

	/**
	 * Rate of factory waste. Initially, this is 1BC per factory.
	 */
	public double wastePerFactory;

	/**
	 * The cleanup cost in BC per unit of waste. Initially, this is 0.5BC per unit of waste.
	 */
	public double cleanupCostPerWaste;

	/**
	 * How much a missile base costs to construct. Initially, this is 245BC.
	 */
	public int missileBaseCost;

	/**
	 * The highest level of planetary shield researched (0=None, 1=Class V, 2=Class X, 3=Class XV, 4=Class XX).
	 */
	public int maxShieldLevel;

	/**
	 * The highest level of planetary environment researched.
	 */
	public Star.Environment maxControlledEnvironment;

	/**
	 * The current treasury amount for this race.
	 */
	public long currentTreasury;

	/**
	 * Total number of research points from all the colonies.
	 */
	public long totalResearchPoints;

	/**
	 * Percentage of research points allocated for Computers.
	 */
	public int computersResearchRatio;

	/**
	 * Percentage of research points allocated for Construction.
	 */
	public int constructionResearchRatio;

	/**
	 * Percentage of research points allocated for Force Field.
	 */
	public int forceFieldResearchRatio;

	/**
	 * Percentage of research points allocated for Planetology.
	 */
	public int planetologyResearchRatio;

	/**
	 * Percentage of research points allocated for Propulsion.
	 */
	public int propulsionResearchRatio;

	/**
	 * Percentage of research points allocated for Weapons.
	 */
	public int weaponsResearchRatio;

	/**
	 * List of ship designs for this race.
	 */
	public final ShipType[] shipTypes = new ShipType[ShipType.TYPE_COUNT];

	/**
	 * Constructor for player and AI race.
	 * 
	 * @param raceIndex
	 * @param bannerIndex
	 * @param leaderName
	 */
	private Race(int raceIndex, int bannerIndex, String leaderName) {
		this.raceIndex = raceIndex;
		this.bannerIndex = bannerIndex;
		this.leaderName = (leaderName != null) ? leaderName : Race.getRaceLeaderName(raceIndex);

		/*
		 * Initialize the initial values of the race specific properties.
		 */
		this.scannerRange = INITIAL_SCANNER_RANGE;
		this.shipRange = ShipType.INITIAL_SHIP_RANGE;
		this.populationCost = POPULATION_COST_INITIAL;
		this.productionPerPopulation = (this.raceIndex == 6) ? KLACKON_PRODUCTION_PER_POPULATION_INITIAL : PRODUCTION_PER_POPULATION_INITIAL;
		this.factoriesPerPopulation = INITIAL_FACTORIES_PER_POPULATION;
		this.factoryCost = FACTORY_COST_10;
		this.wastePerFactory = WASTE_PER_FACTORY_100;
		this.cleanupCostPerWaste = CLEANUP_COST_PER_WASTE_INITIAL;
		this.missileBaseCost = INITIAL_MISSILE_BASE_COST;
		this.computersResearchRatio = INITIAL_COMPUTERS_RP_RATIO;
		this.constructionResearchRatio = INITIAL_CONSTRUCTION_RP_RATIO;
		this.forceFieldResearchRatio = INITIAL_FORCEFIELD_RP_RATIO;
		this.planetologyResearchRatio = INITIAL_PLANETOLOGY_RP_RATIO;
		this.propulsionResearchRatio = INITIAL_PROPULSION_RP_RATIO;
		this.weaponsResearchRatio = INITIAL_WEAPONS_RP_RATIO;
		this.maxControlledEnvironment = (raceIndex == 2) ? Environment.RADIATED : Environment.MINIMAL; // Silicoids can colonize every environment

		/*
		 * Initialize the starting ship designs for the player race or AI race.
		 */
		ShipType.createInitialShipTypes(shipTypes);
	}

	/**
	 * Create the player Race object.
	 * 
	 * @param raceIndex
	 * @param bannerIndex
	 * @param leaderName
	 * @return - the Race object
	 */
	public static Race createPlayerRace(int raceIndex, int bannerIndex, String leaderName) {
		raceAssigned[raceIndex] = true;
		bannerAssigned[bannerIndex] = true;
		Race race = new Race(raceIndex, bannerIndex, leaderName);
		return race;
	}

	/**
	 * Create a random AI player race.
	 * 
	 * @return - the Race object
	 */
	public static Race createRandomRace() {
		int raceIndex = MathUtils.nextRandomInt(0, TOTAL_NO_OF_RACES - 1);
		while (raceAssigned[raceIndex]) {
			if (++raceIndex == TOTAL_NO_OF_RACES)
				raceIndex = 0;
		}
		raceAssigned[raceIndex] = true;
		int bannerIndex = MathUtils.nextRandomInt(0, GameData.TOTAL_NO_OF_BANNERS - 1);
		while (bannerAssigned[bannerIndex]) {
			if (++bannerIndex == GameData.TOTAL_NO_OF_BANNERS)
				bannerIndex = 0;
		}
		bannerAssigned[bannerIndex] = true;
		Race race = new Race(raceIndex, bannerIndex, null);
		return race;
	}

	/**
	 * Returns the race name as an adjective.
	 *
	 * @param raceIndex
	 * @return
	 */
	public static String getRaceName(int raceIndex) {
		return RACE_NAMES[raceIndex][0];
	}

	/**
	 * Returns the race name as a plural.
	 *
	 * @param raceIndex
	 * @return
	 */
	public static String getRaceNamePlural(int raceIndex) {
		return RACE_NAMES[raceIndex][1];
	}

	/**
	 * Returns the race description.
	 *
	 * @param raceIndex
	 * @return
	 */
	public static String getRaceDescription(int raceIndex) {
		return RACE_DESCRIPTIONS[raceIndex];
	}

	/**
	 * Returns a random leader name for the specified race.
	 *
	 * @param raceIndex
	 * @return
	 */
	public static String getRaceLeaderName(int raceIndex) {
		return LEADER_NAMES[raceIndex][MathUtils.nextRandomInt(0, LEADER_NAMES[0].length - 1)];
	}

	/**
	 * Returns the race name as an adjective.
	 *
	 * @return
	 */
	public String getRaceName() {
		return RACE_NAMES[this.raceIndex][0];
	}

	/**
	 * Returns the race name as a plural.
	 *
	 * @return
	 */
	public String getRaceNamePlural() {
		return RACE_NAMES[this.raceIndex][1];
	}

	/**
	 * ` Comment here.
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "Race [(" + raceIndex + ") " + getRaceNamePlural() + '/' + leaderName + '/' + Star.STAR_NAMES[raceIndex + 1] + '/' + bannerIndex + ']';
	}

}
